package cn.itcast.nems.base.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.itcast.ic.common.bean.BizError;
import cn.itcast.ic.common.bean.Page;
import cn.itcast.ic.common.exception.BizException;
import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.ic.msplatform.api.client.DictionaryV3FeignClient;
import cn.itcast.ic.msplatform.api.model.Dictionary;
import cn.itcast.ic.msplatform.api.model.PageData;
import cn.itcast.nems.base.dto.DictionaryDTO;
import cn.itcast.nems.base.service.DictionaryService;
import cn.itcast.nems.common.account.AccountHolder;
import cn.itcast.nems.common.account.AccountInfo;
import cn.itcast.nems.common.enumeration.BaseErrorBodyEnum;
import cn.itcast.nems.common.tenant.TenantInfo;
import cn.itcast.nems.common.tenant.TenantInfoHolder;
import cn.itcast.nems.employee.dao.entity.Employee;
import cn.itcast.nems.employee.service.EmployeeService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DictionaryServiceImpl implements DictionaryService {
    @Autowired
    private DictionaryV3FeignClient dictionaryV3FeignClient;
    @Autowired
    private EmployeeService employeeService;

    @Override
    public List<Dictionary> list(DictionaryDTO params) {
        final Integer tenantId = TenantInfoHolder.getTenantInfo().map(TenantInfo::tenantId).orElse(0);
        String parentCode = params.getParentCode();
        Integer state = params.getState();
        Integer parentId = params.getParentId();
        String code = params.getCode();
        String name = params.getName();
        List<Dictionary> list = dictionaryV3FeignClient.list(tenantId, parentId, parentCode, code, name, state);
        return getDictionarys(list);
    }

    @NotNull
    private List<Dictionary> getDictionarys(List<Dictionary> list) {
        return list.stream().map(dictionary -> {
            String createdBy = dictionary.getCreatedBy();
            String modifiedBy = dictionary.getModifiedBy();
            Employee employeeCreated = employeeService.findOneByEmail(createdBy);
            dictionary.setCreatedName(Objects.nonNull(employeeCreated) ? employeeCreated.getName() : createdBy);
            dictionary.setCreatedByName(Objects.nonNull(employeeCreated) ? employeeCreated.getName() + "（" + employeeCreated.getEmail() + "）" : createdBy);
            Employee employeeModified = employeeService.findOneByEmail(modifiedBy);
            dictionary.setModifieName(Objects.nonNull(employeeModified) ? employeeModified.getName() : modifiedBy);
            dictionary.setModifieByName(Objects.nonNull(employeeModified) ? employeeModified.getName() + "（" + employeeModified.getEmail() + "）" : modifiedBy);
            return dictionary;
        }).collect(Collectors.toList());
    }

    @Override
    public Page<Dictionary> list(Integer pageNumber, Integer pageSize, DictionaryDTO params) {
        final Integer tenantId = TenantInfoHolder.getTenantInfo().map(TenantInfo::tenantId).orElse(0);
        String parentCode = params.getParentCode();
        Integer state = params.getState();
        Integer parentId = params.getParentId();
        String code = params.getCode();
        String name = params.getName();
        PageData<Dictionary> pageData = dictionaryV3FeignClient.list(tenantId, pageNumber, pageSize, parentId, parentCode, code, name, state);
        if (pageData == null || CollectionUtil.isEmpty(pageData.getRecords())) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        List<Dictionary> dictionaryList = pageData.getRecords();
        if (CollectionUtil.isEmpty(dictionaryList)) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        List<Dictionary> list = getDictionarys(dictionaryList);
        return Page.of(pageNumber, pageSize, pageData.getRecordCount(), list);
    }

    @Override
    public Page<Map<String, Object>> listPage(Integer pageNumber, Integer pageSize, DictionaryDTO params) {
        final Integer tenantId = TenantInfoHolder.getTenantInfo().map(TenantInfo::tenantId).orElse(0);
        String parentCode = params.getParentCode();
        Integer state = params.getState();
        Integer parentId = params.getParentId();
        String code = params.getCode();
        String name = params.getName();
        PageData<Dictionary> pageData = dictionaryV3FeignClient.listParentIdsByParentCode(tenantId, pageNumber, pageSize, parentId, parentCode, code, name, state);
        if (pageData == null || CollectionUtil.isEmpty(pageData.getRecords())) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        List<Dictionary> dictionaryList = pageData.getRecords();
        if (CollectionUtil.isEmpty(dictionaryList)) {
            return Page.of(pageNumber, pageSize, 0, null);
        }
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (int i = 0; i < dictionaryList.size(); i++) {
            Dictionary dictionary = JSONObject.toJavaObject((JSON) JSONObject.toJSON(dictionaryList.get(i)), Dictionary.class);
            Map<String, Object> map = new HashMap<>();
            Dictionary dictionary1 = dictionaryV3FeignClient.getById(dictionary.getParentId());
            if (dictionary1 == null) {
                return null;
            }
            // 凭单类型
            map.put("type", dictionary1.getName());
            map.put("parent_code", dictionary1.getCode());
            map.put("id", dictionary.getId());
            map.put("code", dictionary.getCode());
            map.put("parent_id", dictionary.getParentId());

            // 原因
            map.put("name", dictionary.getName());
            // 备注
            map.put("remark", dictionary.getRemark());
            map.put("state", dictionary.getState());
            map.put("created_datetime", LocalDateTimeUtil.formatNormal(dictionary.getCreatedDatetime()));
            map.put("modified_datetime", LocalDateTimeUtil.formatNormal(dictionary.getModifiedDatetime()));
            getCreatedBy(dictionary, map);
            getModifiedBy(dictionary, map);
            mapList.add(map);
        }
        return Page.of(pageNumber, pageSize, pageData.getRecordCount(), mapList);
    }

    private void getCreatedBy(Dictionary dictionary, Map<String, Object> map) {
        String createdBy = dictionary.getCreatedBy();
        if (StringUtils.hasText(createdBy) && !"admin".equals(createdBy)) {
            Employee employee = employeeService.findOneByEmail(createdBy);
            if (employee != null) {
                map.put("created_by", createdBy);
                map.put("created_name", Objects.nonNull(employee) ? employee.getName() : createdBy);
                map.put("created_by_name", Objects.nonNull(employee) ? employee.getName() + "（" + employee.getEmail() + "）" : createdBy);
                return;
            }
        }
        map.put("created_by", "admin");
        map.put("created_name", "admin");
        map.put("created_by_name", "admin");
    }


    private void getModifiedBy(Dictionary dictionary, Map<String, Object> map) {
        String modifiedBy = dictionary.getModifiedBy();
        if (StringUtils.hasText(modifiedBy) && !"admin".equals(modifiedBy)) {
            Employee employee = employeeService.findOneByEmail(modifiedBy);
            if (employee != null) {
                map.put("modifie_by", modifiedBy);
                map.put("modifie_name", Objects.nonNull(employee) ? employee.getName() : modifiedBy);
                map.put("modifie_by_name", Objects.nonNull(employee) ? employee.getName() + "（" + employee.getEmail() + "）" : modifiedBy);
                return;
            }
        }
        map.put("modifie_by", "admin");
        map.put("modifie_name", "admin");
        map.put("modifie_by_name", "admin");
    }

    @Override
    public Integer create(DictionaryDTO params) {
        try {
            final Integer tenantId = TenantInfoHolder.getTenantInfo().map(TenantInfo::tenantId).orElse(0);
            Assert.notNull(tenantId, "tenantId 不能为空");
            Assert.hasText(params.getName(), "name 不能为空");
            Assert.hasText(params.getCode(), "code 不能为空");
            Dictionary dictionary = new Dictionary();
            BeanUtils.copyProperties(params, dictionary);
            dictionary.setTenantId(tenantId);
            final AccountInfo info = AccountHolder.getRequiredAccountInfo();
            if (info != null) {
                dictionary.setCreatedBy(info.getEmail());
            }
//            Map<String, Object> map = JSON.parseObject(JSON.toJSONString(dictionary), Map.class);
            return dictionaryV3FeignClient.create(dictionary);
        } catch (Exception e) {
            log.error("字典添加异常 {}", e.getMessage());
            throw new BizException(BizError.BAD_REQUEST.getStatus(), BizError.BAD_REQUEST.getCode(), e.getMessage().split("\"message\":\"")[1].split("\"}]")[0]);
        }
    }

    @Override
    public Boolean update(DictionaryDTO params) {
        try {
            final Integer tenantId = TenantInfoHolder.getTenantInfo().map(TenantInfo::tenantId).orElse(0);
            Assert.notNull(tenantId, "tenantId 不能为空");
            Assert.hasText(params.getName(), "name 不能为空");
            Assert.hasText(params.getCode(), "code 不能为空");
            Dictionary dictionary = new Dictionary();
            BeanUtils.copyProperties(params, dictionary);
            dictionary.setTenantId(tenantId);
            final AccountInfo info = AccountHolder.getRequiredAccountInfo();
            if (info != null) {
                dictionary.setModifiedBy(info.getEmail());
            }
            Map<String, Object> map = JSON.parseObject(JSON.toJSONString(dictionary), Map.class);
            return dictionaryV3FeignClient.update(map);
        } catch (Exception e) {
            log.error("字典修改异常 {}", e.getMessage());
            throw new BizException(BizError.BAD_REQUEST.getStatus(), BizError.BAD_REQUEST.getCode(), e.getMessage().split("\"message\":\"")[1].split("\"}]")[0]);
        }
    }

    @Override
    public Boolean updateState(Integer id, Integer state) {
        try {
            String email = null;
            final AccountInfo info = AccountHolder.getRequiredAccountInfo();
            if (info != null) {
                email = info.getEmail();
            }
            return dictionaryV3FeignClient.updateState(id, state, email);
        } catch (Exception e) {
            log.error("字典启用/禁用异常 {}", e.getMessage());
            throw new BizException(BizError.BAD_REQUEST.getStatus(), BizError.BAD_REQUEST.getCode(), e.getMessage());
        }
    }


    @Override
    public String getNameByParentCode(String parentCode, String code) {
        if (!StringUtils.hasText(parentCode) || !StringUtils.hasText(code)) {
            return null;
        }
        try {
            final Integer tenantId = TenantInfoHolder.getTenantInfo().map(TenantInfo::tenantId).orElse(0);
            Dictionary dictionary = dictionaryV3FeignClient.getByCode(tenantId, null, parentCode, code);
            if (dictionary == null) {
                return null;
            }
            return dictionary.getName();
        } catch (Exception e) {
            throw new BizException(BizError.BAD_REQUEST.getStatus(), BizError.BAD_REQUEST.getCode(), e.getMessage().split("\"message\":\"")[1].split("\"}]")[0]);
        }
    }

    @Override
    public List<Dictionary> listByName(String parentCode, String itemName) {
        if (!StringUtils.hasText(parentCode) || !StringUtils.hasText(itemName)) {
            return Collections.emptyList();
        }

        List<Dictionary> dictionaries = Collections.emptyList();
        try {
            final Integer tenantId = TenantInfoHolder.getTenantInfo().map(TenantInfo::tenantId).orElse(0);
            dictionaries = dictionaryV3FeignClient.listByName(tenantId, parentCode, itemName);
            if (CollectionUtils.isEmpty(dictionaries)) {
                return Collections.emptyList();
            }
        } catch (Exception e) {
            BizExceptionProducer.throwProduce(e, BaseErrorBodyEnum.ICC_BAD_REQUEST);
        }

        return dictionaries;
    }
}
